<template>
  <div :class="{fullscreen:fullscreen}" class="tinymce-container" :style="{width:containerWidth}">
    <editor :id="tinymceId" v-model="contentHtml" :api-key="apiKey" :init="editorInit"/>
    <div class="editor-custom-btn-container">
      <editorImage color="#1890ff" class="editor-upload-btn" @successCBK="imageSuccessCBK" />
    </div>
  </div>
</template>

<script>
import Editor from '@tinymce/tinymce-vue'
import 'tinymce'
import 'tinymce/models/dom'
import 'tinymce/icons/default'
import 'tinymce/themes/silver/theme'
import 'tinymce/plugins/advlist'
import 'tinymce/plugins/anchor'
import 'tinymce/plugins/autolink'
import 'tinymce/plugins/autoresize'
import 'tinymce/plugins/autosave'
import 'tinymce/plugins/charmap'
import 'tinymce/plugins/code'
import 'tinymce/plugins/codesample'
import 'tinymce/plugins/directionality'
import 'tinymce/plugins/emoticons'
import 'tinymce/plugins/fullscreen'
import 'tinymce/plugins/image'
import 'tinymce/plugins/importcss'
import 'tinymce/plugins/insertdatetime'
import 'tinymce/plugins/link'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/media'
import 'tinymce/plugins/nonbreaking'
import 'tinymce/plugins/pagebreak'
import 'tinymce/plugins/preview'
import 'tinymce/plugins/quickbars'
import 'tinymce/plugins/save'
import 'tinymce/plugins/searchreplace'
import 'tinymce/plugins/table'
import 'tinymce/plugins/template'
import 'tinymce/plugins/visualblocks'
import 'tinymce/plugins/visualchars'
import 'tinymce/plugins/wordcount'
import 'tinymce/plugins/emoticons/js/emojis'
import 'tinymce-paragraphspacing'
import editorImage from './components/EditorImage'
import { getToken } from '@/utils/auth'

const apiKey = 'sq6hvd8ax5xxc0hp8donpjafao6wugysxgd3098xcp9evh86'
const uploadImageUrl = process.env.VUE_APP_BASE_API + process.env.VUE_APP_UPLOAD_BLOG_IMAGE_URL // 上传图片路径
var fullscreen = false

export default {
  name: 'TinyMceEditor',
  components: {
    Editor,
    editorImage
  },
  model: {
    prop: 'content',
    event: 'change'
  },
  props: {
    id: {
      type: String,
      default: function() {
        return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
      }
    },
    // 绑定的文本内容
    content: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      apiKey,
      tinymceFlag: new Date().getTime(),
      tinymceId: this.id,
      selector: `#${this.tinymceId}`,
      fullscreen,
      uploadImageUrl, // 上传图片路径
      headers: this.authorization,
      hasChange: false,
      hasInit: false,
      // 编辑器配置
      editorInit: {
        language_url: '/tinymce/zh_CN.js', // 汉化文件的路径, 这里的原始路径是'/public/zh_CN.js'
        language: 'zh_CN',
        skin: "oxide",
        skin_url: "/tinymce/skins/ui/oxide", // skin路径
        content_css: '/tinymce/skins/content/tinymce-5/content.min.css',
        invalid_styles: {
          'p': 'padding',
        },
        // content_css: 'myLayout.css',
        menubar: true,
        paste_data_images: true, // 设置为“true”将允许粘贴图像，而将其设置为“false”将不允许粘贴图像
        plugins: 'print preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template code codesample table charmap hr pagebreak nonbreaking anchor insertdatetime advlist lists wordcount imagetools textpattern emoticons autosave bdmap indent2em autoresize formatpainter axupimgs toolbarsticky paragraphspacing',
        toolbar: 'undo redo | bold italic underline strikethrough | fontfamily fontsize blocks | alignleft aligncenter alignright alignjustify | outdent indent | lineheight paragraphspacing numlist bullist checklist | forecolor backcolor casechange permanentpen formatpainter removeformat | hr table insertdatetime charmap emoticons codesample | fullscreen preview print | pagebreak blockquote subscript superscript | image media pageembed template link anchor | ltr rtl | showcomments addcomment | footnotes | mergetags',
        height: 800,
        min_height: 600,
        branding: false,
        line_height_formats: '0.5 0.6 0.7 0.8 0.9 1 1.1 1.2 1.3 1.4 1.5 2',
        // toolbar_sticky: true,// toolbar吸顶
        // 自定义图片上传
        images_upload_handler: (blobInfo, progress) => new Promise((resolve, reject) => {
          let xhr, formData;
          // 转化为易于理解的file对象
          const file = blobInfo.blob();
          xhr = new XMLHttpRequest()
          xhr.withCredentials = false
          xhr.open('POST', uploadImageUrl)
          xhr.setRequestHeader('Authorization', this.authorization.Authorization)
          formData = new FormData()
          formData.append('file', file, file.name)// 此处与源文档不一样
          xhr.send(formData)
          xhr.onload = function() {
            let imageUrl;
            const res = JSON.parse(xhr.response.toString());
            if (res.code !== 200) {
              reject('HTTP Error: ' + res.msg)
              return
            }
            imageUrl = res.data.url
            if (!imageUrl) {
              reject('Invalid JSON: ' + res.data)
              return
            }
            resolve(imageUrl)
          }
        }),
        setup(editor) {
          editor.on('FullscreenStateChanged', (e) => {
            this.fullscreen = e.state
          })
        }
      },
      contentHtml: '',
      updateTimer: null // 防抖
    }
  },
  computed: {
    authorization() {
      return {
        Authorization: getToken()
      }
    },
    containerWidth() {
      const width = this.width
      if (/^[\d]+(\.[\d]+)?$/.test(width)) { // matches `100`, `'100'`
        return `${width}px`
      }
      return width
    }
  },
  watch: {
    content: {
      // watch最初绑定的值时候是不会执行的，要等到 content 改变时才执行监听计算。
      // 下面设置可以在content最初绑定的时候就执行监听，否则第一次动态赋值无法触发监听
      handler: function(valueFromParent) {
      // 由父组件自动修改的内容,同步到子组件
        if (valueFromParent !== this.contentHtml) {
          this.contentHtml = valueFromParent
        }
      },
      immediate: true
    },

    contentHtml(valueFromChild) {
      // 向父组件派发change事件
      if (valueFromChild !== this.content) {
        this.updateTimer && clearTimeout(this.updateTimer)
        this.updateTimer = setTimeout(() => {
          this.$emit('change', valueFromChild)
        }, 500)
      }
    }
  },
  beforeDestroy() {
    this.updateTimer && clearTimeout(this.updateTimer)
  },
  deactivated() {
    this.destroyTinymce()
  },
  destroyed() {
    this.destroyTinymce()
  },
  methods: {
    // 图片上传后，在编辑器中显示
    imageSuccessCBK(arr) {
      arr.forEach(v => {
        window.tinymce.get(this.tinymceId).insertContent(`<img style="max-width: 100%" class="wscnph" src="${v.url}" alt=""/>`)
      })
    },
    setContent(value) {
      window.tinymce.get(this.tinymceId).setContent(value)
    },
    getContent() {
      window.tinymce.get(this.tinymceId).getContent()
    },
    destroyTinymce() {
      const tinymce = window.tinymce.get(this.tinymceId)
      if (this.fullscreen) {
        tinymce.execCommand('mceFullScreen')
      }
      if (tinymce) {
        tinymce.destroy()
      }
    }
  }
}
</script>
<style lang="scss">
.tinymce-container {
  position: relative;
  line-height: normal;
}

.tox-editor-header-fixed{
  top: 20px;
  position: fixed;
}

.tinymce-textarea {
  visibility: hidden;
  z-index: -1;
}
.editor-custom-btn-container {
  position: absolute;
  right: 4px;
  top: 4px;
  z-index: 2020;
}

.editor-custom-btn-container-fixed {
  position: fixed !important;
  top: 53px !important;
  right: 31px !important;
}

/* 兄弟选择器 */
.tox-fullscreen + .editor-custom-btn-container {
  position: fixed;
  right: 4px;
  top: 4px;
}
.editor-upload-btn {
  display: inline-block;
}
.tox-tinymce-aux{
  z-index: 9950 !important;
}
.tox .tox-promotion {
  display: none;
}
</style>
